package com.googlecode.connectlet.tsa;

import java.io.IOException;
import java.security.Signature;
import java.security.cert.X509Certificate;

import sun.security.pkcs.ContentInfo;
import sun.security.pkcs.PKCS7;
import sun.security.pkcs.SignerInfo;
import sun.security.util.DerValue;
import sun.security.util.ObjectIdentifier;
import sun.security.x509.AlgorithmId;
import sun.security.x509.X500Name;

import com.googlecode.connectlet.util.secure.CertKey;
import com.googlecode.connectlet.util.secure.CertMap;

public class P7S {
	public static PKCS7 sign(byte[] content, CertKey... certKeys) throws IOException {
		return sign(null, content, certKeys);
	}

	public static PKCS7 sign(ObjectIdentifier oid, byte[] content,
			CertKey... certKeys) throws IOException {
		Signature signature;
		try {
			signature = Signature.getInstance("MD5withRSA");
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		SignerInfo[] signerInfos = new SignerInfo[certKeys.length];
		CertMap certMap = new CertMap();
		for (int i = 0; i < certKeys.length; i ++) {
			certMap.add(certKeys[i].getCertificateChain());
			X509Certificate cert = certKeys[i].getCertificateChain()[0];
			X500Name issuer = new X500Name(cert.getIssuerX500Principal().getEncoded());
			try {
				signature.initSign(certKeys[i].getKey());
				signature.update(content);
				signerInfos[i] = new SignerInfo(issuer, cert.getSerialNumber(),
						new AlgorithmId(AlgorithmId.MD5_oid),
						new AlgorithmId(AlgorithmId.RSAEncryption_oid), signature.sign());
			} catch (Exception e) {
				throw new IOException(e);
			}
		}
		ContentInfo contentInfo = (oid == null ? new ContentInfo(content) :
				new ContentInfo(oid, new DerValue(DerValue.tag_OctetString, content)));
		return new PKCS7(new AlgorithmId[] {new AlgorithmId(AlgorithmId.MD5_oid)},
				contentInfo, certMap.values().toArray(new X509Certificate[0]), signerInfos);
	}

	public static boolean verify(PKCS7 pkcs7, CertMap certMap) throws Exception {
		SignerInfo[] signerInfos = pkcs7.verify();
		if (signerInfos != null) {
			for (SignerInfo signerInfo : signerInfos) {
				Object[] objs = signerInfo.getCertificateChain(pkcs7).toArray();
				X509Certificate[] certChain = new X509Certificate[objs.length];
				System.arraycopy(objs, 0, certChain, 0, objs.length);
				if (certMap.verify(certChain)) {
					return true;
				}
			}
		}
		return false;
	}
}